package com.hr;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.espirit.common.Form;
import com.espirit.common.FormService;
import com.espirit.eap.manager.DepartmentService;
import com.espirit.eap.sa.Employee;
import com.espirit.eap.util.BigDecimalUtil;
import com.espirit.eap.util.DateUtils;
import com.googlecode.cswish.annotation.ParamScope;
import com.googlecode.cswish.annotation.Rest;
import com.googlecode.cswish.exception.ApplicationException;
import com.googlecode.cswish.model.PageElements;
import com.googlecode.cswish.model.PageInfo;
import com.googlecode.cswish.model.ParameterMap;
import com.googlecode.cswish.model.Reference;
import com.googlecode.cswish.oosearch.QLInfo;
import com.googlecode.cswish.struts.spring.GenericService;
import com.googlecode.cswish.struts.spring.ObjectFactory;
import com.googlecode.cswish.struts.spring.SearchCallback;

@Service
public class LeaveAppItemService extends FormService{
	@Resource
	GenericService genericService;
	
	@Resource
	DepartmentService departmentService;
	
//	@Resource
	SalaryService salaryService;
	
	public  PageInfo search(final ParameterMap model, int start, int limit,
    		String sort, String dir, boolean newSearch, Reference<QLInfo> qlInfoRef,
    		@ParamScope(visible=false, value="#ps")PageElements ps ,boolean fromMenu
    		) {
		
		SearchCallback callback = departmentService.buildDeptDefaultSearchCallback(model, null, null);
		return genericService.search(model, start, limit, sort, dir, newSearch, qlInfoRef, callback, true, false);
	}
	
	@Rest(type="search")
	public PageInfo searchRelatedResult(Salary model){
		model = genericService.load(model);
		if (model == null) return null;
		int year = model.getAcctTerm().getYear();
		int month = model.getAcctTerm().getMonth();
		
		final Date monthStart = DateUtils.generateMonthStart(year, month);
		final Date monthEnd = DateUtils.generateMonthEnd(year, month);
		
		List<LeaveAppItem> data = getEmployeeLeaveAppItems(model.getEmployee(), monthStart, monthEnd);
		if (data == null) return null;
		
		PageInfo pageInfo = new PageInfo();
		pageInfo.setData(data);
		pageInfo.setPageSize(data.size());
		return pageInfo;
	}
	
	//TODO query employee's leaveAppItems by date range
	public List<LeaveAppItem> getEmployeeLeaveAppItems(Employee emp, Date timeFrom, Date timeTo) {
		List<LeaveAppItem> ret = new ArrayList<LeaveAppItem>();
		
		final String hql = String.format("from " +  LeaveAppItem.class.getName() + " a where a.employee.id = '%s' and (a.beginTime BETWEEN '%s' and '%s' or a.endTime between '%s' and '%s')", 
				emp.getId(), 
				DateUtils.format(timeFrom, "yyyy-MM-dd HH:mm:ss"), DateUtils.format(timeTo, "yyyy-MM-dd HH:mm:ss"), 
				DateUtils.format(timeFrom, "yyyy-MM-dd HH:mm:ss"), DateUtils.format(timeTo, "yyyy-MM-dd HH:mm:ss")
				);
		
		QLInfo qlInfo = new QLInfo(hql, true);
		ret.addAll(genericService.searchByQl(qlInfo, false).getData());
		return ret;
	}

	public void 
	deleteLeaveApp(Employee emp, Date timeFrom, Date timeTo) {
		List<LeaveAppItem> leaveAppItems = getEmployeeLeaveAppItems(emp, timeFrom, timeTo);
		
		for (LeaveAppItem leaveAppItem : leaveAppItems) {
			genericService.delete(leaveAppItem);
		}
	}
	
	@Override
	protected boolean preAdd(Form model) {
		LeaveAppItem form = (LeaveAppItem) model;
		checkEmployeeExchangeHours(form, form.getHours());
		return true;
	}
	
	
	@Override
	protected void postAdd(Form model) {
		getSalaryService().reCalEmpSalary(model.getEmployee());
		super.postAdd(model);
	}
	
	@Override
	protected boolean preUpdate(Form model) {
		LeaveAppItem form = (LeaveAppItem) model;
		LeaveAppItem orig = genericService.load(form);
		BigDecimal origHours = BigDecimalUtil.getValue(orig.getHours());
		BigDecimal nowHours = BigDecimalUtil.getValue(form.getHours());
		BigDecimal diff = nowHours.subtract(origHours);
		checkEmployeeExchangeHours(form, diff);
		
		return true;
	}
	
	@Override
	protected void postUpdate(Form model) {
		
		getSalaryService().reCalEmpSalary(model.getEmployee());
		
		super.postUpdate(model);
	}
	
	@Transactional
	public void deleteList(List<LeaveAppItem> results){
		if (results == null) return ;
		for(LeaveAppItem leaveAppItem : results){
			if (leaveAppItem == null || leaveAppItem.getId() == null) continue;
			leaveAppItem = genericService.load(LeaveAppItem.class, leaveAppItem.getId());
			if (leaveAppItem != null && LeaveAppItem.LEAVE_TYPE_EXCHANGING.equals(leaveAppItem.getLeaveType())){
				BigDecimal hours = BigDecimalUtil.getValue(leaveAppItem.getHours());
				
				Employee employee = leaveAppItem.getEmployee();
				if (employee != null){
					BigDecimal exchangeHours = BigDecimalUtil.getValue(employee.getExchangeHours());
					exchangeHours = exchangeHours.add(hours);
					employee.setExchangeHours(exchangeHours);
					genericService.merge(employee);
				}
			}
			Employee emp = leaveAppItem.getEmployee();
			genericService.delete(leaveAppItem);
			
			getSalaryService().reCalEmpSalary(emp);
		}
	}
	
	private void checkEmployeeExchangeHours(LeaveAppItem model, BigDecimal hours){
		if (model == null) return ;
		if (model.getEmployee() == null || model.getEmployee().getId() == null) return ;
		if ( LeaveAppItem.LEAVE_TYPE_EXCHANGING.equals(model.getLeaveType())){
			Employee emp = genericService.load(Employee.class, model.getEmployee().getId());
			hours = BigDecimalUtil.getValue(hours);
			
			BigDecimal empExchangeHours = BigDecimalUtil.getValue(emp.getExchangeHours());
			
			if (hours.compareTo(empExchangeHours) > 0 ) {
				throw new ApplicationException("请假（调休）时间不能大于有效调休时间", emp.getExchangeHours());
			}
			empExchangeHours = empExchangeHours.subtract(hours);
			emp.setExchangeHours(empExchangeHours);
			genericService.merge(emp);
		}
	}
	
	public SalaryService getSalaryService(){
		if (salaryService == null){
			salaryService = ObjectFactory.getInstance().getBean(SalaryService.class, true);
		}
		return salaryService;
	}
}
